import {NodePath, PluginObj, transformFromAstSync} from "@babel/core";
import {parse} from "@babel/parser";
import template from "@babel/template";
import {
    addComment,
    ExportNamedDeclaration,
    Identifier,
    isExportNamedDeclaration, isFunctionDeclaration, isVariableDeclaration,
    Program,
    Statement,
} from "@babel/types";
import prettier from "prettier";
import * as fs from "node:fs";
import camelCase from "camelcase";
import {Dict} from "../types.js";

function addDictFunc(path: NodePath<Program>, dict: Dict, lastVarIdx: number) {
    const idx = path.node.body.findIndex((statement: Statement) => {
        if (isExportNamedDeclaration(statement)) {
            const declaration = statement.declaration;
            if (isVariableDeclaration(declaration)) {
                const variableDeclarator = declaration.declarations[0];
                return (
                    (variableDeclarator.id as Identifier).name ===
                    camelCase(dict.name) + "Select"
                );
            }
            return false;
        }
        return false;
    });
    if (idx >= 0) {
        return;
    }
    const ast = template.statement(`
        export const ${camelCase(dict.name)}Select = ${JSON.stringify(dict.select)}
        `)();
    addComment(ast, "leading", `*\n* ${dict.comment}\n`, false);
    path.node.body.splice(lastVarIdx, 0, ast);
}

function addTranslateFunc(path: NodePath<Program>) {
    const checkMethods = ["translate2Label", "translate2Value"];
    const asts = [
        template.statement(`
                    export function translate2Label(select, value) {
                        const find = select.find(item => item.value === value);
                        if (find) {
                            return find.label;
                        }
                        return undefined;
                    }
                    `)(),
        template.statement(`
                    export function translate2Value(select, label) {
                        const find = select.find(item => item.label === label);
                        if (find) {
                            return find.value;
                        }
                        return undefined;
                    }
                    `)(),
    ];
    const method = (methodName: string, ast: Statement) => {
        const idx = path.node.body.findIndex((statement: Statement) => {
            if (isExportNamedDeclaration(statement)) {
                const declaration = statement.declaration;
                if (isFunctionDeclaration(declaration)) {
                    return declaration.id?.name === methodName;
                }
                return false;
            }
            return false;
        });
        if (idx >= 0) {
            return;
        }
        path.node.body.push(ast);
    };

    for (let i = 0; i < checkMethods.length; i++) {
        const checkMethod = checkMethods[i];
        const ast = asts[i];
        method(checkMethod, ast);
    }
}

export async function genFile(path: string, dicts: Dict[]) {
    let sourceCode: string;
    if (!fs.existsSync(path)) {
        fs.writeFileSync(path, "");
        sourceCode = "";
    } else {
        sourceCode = fs.readFileSync(path, {encoding: "utf-8"});
    }
    const ast = parse(sourceCode, {
        sourceType: "module",
        // plugins: ['typescript']
        // plugins: ["decorators"]
    });

    function myPlugin(): PluginObj {
        return {
            visitor: {
                Program(path: NodePath<Program>) {
                    let idx = 0;
                    if (path.node.body.length > 0) {

                        while (idx < path.node.body.length && isExportNamedDeclaration(path.node.body[idx])) {
                            const exportNamedDeclaration = path.node.body[
                                idx
                                ] as ExportNamedDeclaration;
                            if (!isVariableDeclaration(exportNamedDeclaration.declaration)) {
                                break;
                            }
                            idx++;
                        }
                    }
                    for (let dict of dicts) {
                        addDictFunc(path, dict, idx);
                    }

                    addTranslateFunc(path);
                },
            },
        };
    }

    const res = transformFromAstSync(ast, sourceCode, {
        plugins: [myPlugin],
        retainLines: true,
    });

    const formatedCode = await prettier.format(res?.code!, {
        filepath: path,
        endOfLine: "lf",
        bracketSpacing: true,
    });
    fs.writeFileSync(path, formatedCode, {encoding: "utf-8"});
}

// async function main() {
//     const string = fs.readFileSync("./target.json", {encoding: "utf-8"});
//     const dicts = JSON.parse(string) as Dict[];
//     await genFile("./target.js", dicts);
// }
//
// await main();
